Service Accounts#3058
Open
GregorShear wants to merge 5 commits into
Open
Conversation
faf9471 to
92dd836
Compare
92dd836 to
35ff08b
Compare
GregorShear
commented
Jun 19, 2026
| .map_err(duplicate_err)?; | ||
|
|
||
| for grant in &grants { | ||
| crate::grants::overwrite_user_grant( |
Contributor
Author
There was a problem hiding this comment.
I have mixed feelings about doing this in the create mutation - maybe we need an "update grant" mutation that lets us downgrade capabilities, and the create mutation just upserts (upgrade capabilities only)?
GregorShear
commented
Jun 19, 2026
GregorShear
commented
Jun 19, 2026
|
|
||
| # Run last so its flakiness can't skip the test steps above. It still gates | ||
| # the job on failure, surfacing genuine Stripe regressions. | ||
| - name: Stripe integration test |
Contributor
Author
There was a problem hiding this comment.
moving this flaky test to the end of the line, at least for now
2052d3d to
03fa4db
Compare
03fa4db to
be5fca4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Service accounts
Non-login identities for CI/CD and automation. A service account is a real
auth.usersrow authorized through ordinaryuser_grants, so RLS,user_roles()resolution, and role traversal work unchanged. It's addressed by a unique catalog name (e.g.acmeCo/ci-bot) that acts as a management anchor: holders of the new service-account capabilities on a covering prefix manage the account. The account's own access comes solely from its grants, which may span prefixes.Schema: new
internal.service_accountstable (uniquecatalog_name, SP-GiST-indexed for prefix scoping) and arefresh_tokens.created_bycolumn recording the minting admin.API keys are refresh tokens
There is no bespoke credential type.
createApiKeymints a multi-use refresh token owned by the account and returns the bearer secret exactly once, in the base64{id, secret}form thatAuthorization: BearerandPOST /api/v1/auth/tokenalready accept. Revoking zeroesvalid_for: the token becomes inert immediately (every request re-verifies against the database) while the row survives for audit.revokeAllApiKeysis the credential kill switch.Service accounts cannot self-manage credentials:
createRefreshToken/revokeRefreshTokenreject service-account callers, so a leaked key can't mint its own replacements or revoke outside the admin flow. (A residual self-service surface exists via PostgREST'srefresh_tokensgrants; it disappears with PostgREST.)Authorization
Four new fine-grained capabilities (
QueryServiceAccounts,CreateServiceAccount,CreateApiKey,RevokeApiKey), bundled asmanage_service_accountand included inteam_admin:serviceAccountsqueryQueryServiceAccountson a covering prefixcreateServiceAccountCreateServiceAccounton the catalog name, plusCreateGranton each seeded grant prefixaddServiceAccountGrantCreateGranton the granted prefixremoveServiceAccountGrant/removeAllServiceAccountGrantsCreateServiceAccounton the catalog namecreateApiKeyCreateApiKeyon the catalog namerevokeApiKey/revokeAllApiKeysRevokeApiKeyon the catalog nameThe per-prefix
CreateGrantcheck on add is the anti-escalation guard: a manager can't hand an account reach they couldn't grant anyone. Removal has no per-prefix requirement since it only narrows access. Re-adding an existing grant overwrites its capability, so downgrades work in one call.Also in this PR
SensitiveGraphQL scalar for one-time secrets: serializes as a string, redactingDebug, and distinct in the schema so client tooling can recognize and redact it. Applied to API-key, refresh-token, and Stripe setup-intent secrets.POST /api/v1/auth/tokennow share onegenerate_access_token, so credential-error sanitization lives in one place.@service_accounts.estuary.devaddresses must never become a tenant's billing contact.Testing
sqlx tests cover the lifecycle end to end: create with multi-grant seeding, mint, list (including derived
lastUsedAt), revoke and kill switches with idempotency, self-management rejection, duplicate catalog names,validForvalidation, and grant add/remove/overwrite semantics. A second test verifies ateam_adminholder without fullAdmincan manage accounts whileCreateGrantstill bounds escalation. The JWT-signing exchange path is covered by existing pgTAP tests.